﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Diagnostics;
using SimpleIR;

namespace InterpreterCore
{
	/// <summary>
	/// Implements a struct representing simple memory values (numbers or pointers) that can be stored in struct/class fields.
	/// </summary>
	internal struct SimpleMemoryValue
	{
		/// <summary>
		/// Value if the type is a signed number.
		/// </summary>
		private readonly NumericValue m_numval;

		/// <summary>
		/// Value if the type is a pointer.
		/// </summary>
		private readonly PtrValue m_ptrval;

		private SimpleMemoryValue(NumericValue nv)
		{
			this.m_numval = nv;
			this.m_ptrval = PtrValue.MakeNullPtr(null);
		}

		private SimpleMemoryValue(PtrValue pv)
		{
			this.m_numval = NumericValue.MakeZeroValueOfType(null);
			this.m_ptrval = pv;
		}

		public override string ToString()
		{
			if(this.m_ptrval.ValType != null)
				return this.m_ptrval.ToString();
			else
				return this.m_numval.ToString();
		}

		internal string DebuggerString()
		{
			if(this.m_ptrval.ValType != null)
				return this.m_ptrval.DebuggerString();
			else
				return this.m_numval.DebuggerString();
		}

		internal string EmitForTrace()
		{
			if(this.m_ptrval.ValType != null)
				return this.m_ptrval.EmitForTrace();
			else
				return this.m_numval.EmitForTrace();
		}

		internal void SerializeForHeapDump(System.IO.TextWriter dumpstr)
		{
			if(this.m_ptrval.ValType != null)
				this.m_ptrval.SerializeForHeapDump(dumpstr);
			else
				this.m_numval.SerializeForHeapDump(dumpstr);
		}

		internal static SimpleMemoryValue ParseValue(IRType pvt, string val)
		{
			if(pvt is IRPtrType)
				return new SimpleMemoryValue(PtrValue.ParseValue((IRPtrType)pvt, val));
			else
			{
				IRPrimitiveNumericType ntype = (pvt is IREnumType) ? ((IREnumType)pvt).UnerlyingNumericType : ((IRPrimitiveNumericType)pvt);
				return new SimpleMemoryValue(NumericValue.ParseValue(ntype, val));
			}
		}

		///////////////////////////////////////////////////////////////////////////////
		//How to convert passable numeric and pointer values to/from the simple memory versions.

		internal static SimpleMemoryValue MakeInitialSimpleMemoryValueOfType(IRType tt)
		{
			if(tt is IREnumType)
				return new SimpleMemoryValue(NumericValue.MakeZeroValueOfType(((IREnumType)tt).UnerlyingNumericType));
			else if(tt is IRPrimitiveNumericType)
				return new SimpleMemoryValue(NumericValue.MakeZeroValueOfType((IRPrimitiveNumericType)tt));
			else
				return new SimpleMemoryValue(PtrValue.MakeNullPtr((IRPtrType)tt));
		}

		internal PtrValue ConvertToPassablePtrValue()
		{ return this.m_ptrval; }

		internal static SimpleMemoryValue ConvertPtrValToSimpleMemoryVersion(PtrValue pv)
		{ return new SimpleMemoryValue(pv); }

		internal NumericValue ConvertToPassableNumericValue()
		{ return this.m_numval; }

		internal static SimpleMemoryValue ConvertNumericValToSimpleMemoryVersion(NumericValue nv)
		{ return new SimpleMemoryValue(nv); }
	}
}
